﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data;
using System.Text;
using AutoMapper;
using Jb.Common.Extensions;
using Jb.Domain;
using Jb.Web.ViewModels;
using Jb.Web.Utility;
using Jb.Common.Xml;
using Jb.Web.ViewModels.UtilityModels;
using Jb.Search;

namespace Jb.Web.Areas.Private.Controllers
{
    [Authorize(Roles = "Company Admin,Company User,Admin")]
    public class JobController : BaseController
    {
		private JbEntities _Context = new JbEntities();
        
		#region Constructors
		public JobController()
		{
		}

		public JobController(UserViewModel currentUser)
			: base(currentUser)
        {
        }
		#endregion Constructors

		#region Action Methods

        /// <summary>
        /// Gets a list of all jobs, it does the same as list Action Method
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult Index(String pageNo = null)
        {
            return View("List", BuildListConfig(pageNo.ToInt() > 0 ? pageNo.ToInt() : 1));
        }

        /// <summary>
        /// Gets a list of all jobs
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult List(String pageNo = null)
        {
            ViewData[AppConstants.ViewDataKeys.SHOW_APPLICATION_COUNT] = true;
            return View(BuildListConfig(pageNo.ToInt() > 0 ? pageNo.ToInt() : 1));
        }


		/// <summary>
        /// Gets a Job from Database to edit
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult Edit(int id = 0, String IsSaved = null, String type = null)
        {
            Job entity = _Context.Jobs.Include("JobEducations").Include("JobSkills").Include("City").FirstOrDefault(P => P.ID == id);
            if (entity == null && id > 0)
                return View();

            if (entity == null)
            {
                entity = new Job();
                entity.CompanyID = LoggedInUser.Contact.CompanyID;
                entity.IsActive = true;
                entity.SendExpireAlert = true;
            }
            if (entity.CompanyID != LoggedInUser.Contact.CompanyID)
                return base.RedirectToAccessDenied();
            
            JobViewModel viewModel = Mapper.Map<Job, JobViewModel>(entity);

            if (id > 0)
            {
                viewModel.CountryID = entity.City.State.CountryID;
                viewModel.StateID = entity.City.StateID;
            }
            
            ///Map Education and Skills
            MapEducationAndSkill(entity, viewModel);

            TempData[AppConstants.ViewDataKeys.SAVED] = IsSaved;
            return View(viewModel);
        }        

		/// <summary>
        /// Saves Job Information into the Database
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
		[HttpPost]
		public ActionResult Edit(JobViewModel viewModel)
        {
			if (!ModelState.IsValid)
                return View(viewModel);

            bool hasValidationError = false;
            DateTime postDate = viewModel.PostDate.ToDateTime(ConfigReader.CSharpCalendarDateFormat);
            DateTime endDate = viewModel.EndDate.ToDateTime(ConfigReader.CSharpCalendarDateFormat);

            if (endDate <= postDate)
            {
                ModelState.AddModelError("EndDate", "Sorry! End Date Must be greater than Post Date.");
                hasValidationError = true;
            }

            if (hasValidationError)
            {
                ViewData[AppConstants.ViewDataKeys.HAS_VALIDATION_ERROR] = true;
                //Prepare the lglValue XML and Store it in a hidden field with URL Encode.
                // Then the JS will call with this lglValue to regenerate the Dynamic Category UI.
                if (viewModel.CategoryID > 0)
                {
                    Job fallbackEntity = new Job();
                    fallbackEntity.ID = viewModel.ID;
                    fallbackEntity.CategoryID = viewModel.CategoryID;
                    StringBuilder searchData = new StringBuilder();
                    setDynamicProperties(fallbackEntity, ref searchData);
                    viewModel.DynamicProperties = fallbackEntity.DynamicProperties;
                }
                return View(viewModel);
            }

            Job entity = null;
            DateTime createdOn = DateTime.Now;
            bool oldIsActive = false;
            if (viewModel.ID == 0)
            {
                entity = new Job();
                _Context.AddToJobs(entity);
            }
            else
            {
                entity = _Context.Jobs.FirstOrDefault(P => P.ID == viewModel.ID);                
                if (entity == null || entity.CompanyID != LoggedInUser.Contact.CompanyID)
                    return base.RedirectToAccessDenied();
                createdOn = entity.CreatedOn;
                oldIsActive = entity.IsActive;
            }
            viewModel.Url = viewModel.Title.ToSeoUrl();

            entity = Mapper.Map<JobViewModel, Job>(viewModel, entity);
            
            ///Need to Set few properties after Automapper Mapping
            if (entity.ID == 0)
            {   
                //TODO: Unique Identifier Need to change for MySQL
                entity.ActivationKey = System.Guid.NewGuid();
                //entity.ActivationKey = System.Guid.NewGuid().ToString();
            }

            entity.CreatedOn = createdOn;
            entity.CompanyID = LoggedInUser.Contact.CompanyID;      
            entity.ModifiedOn = DateTime.Now;
            entity.ModifiedBy = LoggedInUser.ID;

            StringBuilder dynamicProperties = new StringBuilder();
            setDynamicProperties(entity, ref dynamicProperties);
            _Context.SaveChanges();

            ///Set Education and Skill from ViewModel to Entity Object
            SetJobEducations(entity, viewModel);
            SetJobSkills(entity, viewModel);
            _Context.SaveChanges();
            ///Fire External Events
            if (viewModel.ID == 0)
                JbEvents.JobAdded(entity, _Context);
            else
                JbEvents.JobUpdated(entity, oldIsActive, _Context);            

            String url = String.Format("Edit/{0}", entity.ID);
            String listType = WebUtil.GetQueryStringValue("Type");
            if(listType.IsNullOrEmpty())
                return RedirectToAction(url, new { IsSaved = "True"});
            else
                return RedirectToAction(url, new { IsSaved = "True", Type = listType });
        }        

        /// <summary>
        /// Gets a List of Published Jobs ordered by most recent published date
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        //public ActionResult PublishedJobs(String id)
        //{
        //    ViewData[AppConstants.ViewDataKeys.GENERIC_KEY] = true;
        //    ViewData[AppConstants.ViewDataKeys.SHOW_APPLICATION_COUNT] = true;
        //    return View("List", BuildListConfig(id, true));
        //}

        /// <summary>
        /// Generates the Product Entry Form According to the Selected Categry
        /// </summary>
        /// <param name="jobID"></param>
        /// <param name="categoryID"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateInput(false)]
        public PartialViewResult GetDynamicUI(int jobID, int categoryID, String lglValues = null)
        {
            Category category = _Context.Categories.FirstOrDefault(P => P.ID == categoryID);
            if (category != null)// && !category.PropertyDefinition.IsEmpty())
            {
                ///Overridable ZGL
                String ZGL = String.Empty;
                if (!category.PropertyDefinition.IsEmpty())
                    ZGL = category.PropertyDefinition;
                else if (category.ParentCategory != null && category.PropertyDefinition.IsEmpty() && !category.ParentCategory.PropertyDefinition.IsEmpty())
                    ZGL = category.ParentCategory.PropertyDefinition;

                if (!ZGL.IsEmpty())
                {
                    Job job = null;
                    if (jobID > 0)
                        job = _Context.Jobs.FirstOrDefault(P => P.ID == jobID);
                    else
                        job = new Job();

                    JobViewModel jobViewModel = Mapper.Map<Job, JobViewModel>(job);
                    if (!lglValues.IsNullOrEmpty())
                        jobViewModel.DynamicProperties = lglValues.UrlDecode();

                    WebUtil.MapZGL(jobViewModel, ZGL);

                    //ViewBag.Product = productViewModel;
                    //ViewBag.Category = Mapper.Map<Category, CategoryViewModel>(category, new CategoryViewModel());
                    return PartialView("_ZGLJobUI", jobViewModel);
                }
            }
            return null;
        }

        /// <summary>
        /// Tries to delete a job       
        /// </summary>
        /// <param name="jobID"></param>
        /// <returns>Different Status messages. And they are
        /// -1  -> Could not found job for delete
        /// -2  -> This job has applications
        /// -3  -> This is a favorite job
        /// -4  -> Permission Denied
        /// +1  -> Successfully deleted job
        /// +2  -> Forcefully Deleted Job
        /// </returns>
        public int DeleteJob(int jobID, String forceDelete)
        {
            bool isForceDelete = forceDelete.ToBoolean();

            Job job = _Context.Jobs.FirstOrDefault(P => P.ID == jobID);
            if (job == null)
                return -1;            
            if (job.CompanyID != LoggedInUser.Contact.CompanyID)
                return -4;
            if (isForceDelete)
            {
                ///Delete Short listed Jobs
                //foreach (var jobApplication in job.JobApplications.ToList())
                //{
                //    _Context.DeleteObject(jobApplication);
                //}
                /////Delete Short listed Resumes
                //foreach (var favoriteResume in job.FavoriteResumes.ToList())
                //{
                //    _Context.DeleteObject(favoriteResume);
                //}
                DeleteJob(job);
                return job.IsActive ? 2 : 22;
            }
            else
            {
                if (job.JobApplications.Count > 0)
                    return -2;
                else if (job.FavoriteResumes.Count > 0)
                    return -3;

                DeleteJob(job);
                return job.IsActive ? 1 : 11;

            }
        }
		#endregion Action Methods
		
		#region Helper Methods

        /// <summary>
        /// Builds a ListConfig object for job listing
        /// </summary>
        /// <param name="id">This is pageNo as it comes in the query string</param>
        /// <param name="getActiveOnly">If true gets only active jobs otherwise all of them</param>
        /// <returns></returns>
        private ListConfig BuildListConfig(int pageNo)
        {
            bool getPublishedOnly = String.Compare(WebUtil.GetQueryStringValue("Type"), "P", true) == 0 ? true : false;
            //int pageNo = id.ToInt() > 0 ? id.ToInt() : 1;
            UtilityDAO dao = new UtilityDAO();
            Jb.Domain.DbParameter[] parameters = new[]{
                new Jb.Domain.DbParameter("@CompanyID", LoggedInUser.Contact.CompanyID),
                new Jb.Domain.DbParameter("@GetPublishedOnly", getPublishedOnly)
            };
            int totalRecord = 0;
            DataSet ds = dao.GetPagedData(DbObject.SP.GET_PAGED_JOB_LIST_BY_COMPANY, parameters, pageNo, ConfigReader.PageSizeOfCompanyJobList, out totalRecord, true);

            ViewModels.UtilityModels.PagerConfig pagerConfig = new ViewModels.UtilityModels.PagerConfig(pageNo, ConfigReader.PageSizeOfCompanyJobList, totalRecord);
            if (getPublishedOnly)
                pagerConfig.UrlFormat = "/Private/Job/List?Type=P&PageNo={0}";
            else
                pagerConfig.UrlFormat = "/Private/Job/List?PageNo={0}";
            ListConfig listConfig = new ListConfig(ds.Tables[0], pagerConfig);
            return listConfig;
        }

        /// <summary>
        /// Deletes Job Index, the job object is marked for delete and Reloads Job Searcher.
        /// </summary>
        /// <param name="job"></param>
        private void DeleteJob(Job job)
        {
            IIndexer indexer = IndexerFactory.GetIndexer(typeof(Job));
            indexer.DeleteIndex(job.ID);
            indexer.CommitChanges();
            indexer.CloseWriter();
            ///Reload Index Searcher
            ISearcher jobSearcher = SearcherFactory.GetSearcher(typeof(Job));
            jobSearcher.Reload();

            job.IsDeleted = true;
            job.ModifiedBy = LoggedInUser.ID;
            job.ModifiedOn = DateTime.Now;            
            _Context.SaveChanges();
            JbEvents.JobDeleted(job, _Context);
        }

        /// <summary>
        /// Set Dynamic Properties to Save in the Database as XML String
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="dynamicSearchableData">Sets the Dynamic Search Data During Searching Product Properties</param>        
        private void setDynamicProperties(Job entity, ref StringBuilder dynamicSearchableData)
        {
            Category category = _Context.Categories.FirstOrDefault(P => P.ID == entity.CategoryID);
            if (category != null )//&& !category.PropertyDefinition.IsEmpty())
            {
                ///Overridable ZGL
                String ZGL = String.Empty;
                if(!category.PropertyDefinition.IsEmpty())
                    ZGL = category.PropertyDefinition;
                else if (category.ParentCategory != null && category.PropertyDefinition.IsEmpty() && !category.ParentCategory.PropertyDefinition.IsEmpty())
                    ZGL = category.ParentCategory.PropertyDefinition;
                 

                if (!ZGL.IsEmpty()) ///ZGL Exists for this category
                {
                    Jb.Web.ViewModels.ZGL.Category.Category categoryZGL = XmlHelper.ToObject<Jb.Web.ViewModels.ZGL.Category.Category>(ZGL);
                    if (categoryZGL == null)
                        entity.DynamicProperties = null;
                    else
                    {
                        ViewModels.ZGL.Product.Product productLGL = new ViewModels.ZGL.Product.Product();
                        productLGL.Property = new List<ViewModels.ZGL.Product.ProductProperty>();
                        foreach (Jb.Web.ViewModels.ZGL.Category.ProductGroup group in categoryZGL.Group)
                        {
                            foreach (Jb.Web.ViewModels.ZGL.Category.ProductGroupProperty property in group.Property)
                            {
                                ViewModels.ZGL.Product.ProductProperty productProperty = new ViewModels.ZGL.Product.ProductProperty();
                                productProperty.Name = property.Name;
                                productProperty.Value = Request.Form[getDynamicControlName(property.Name)];
                                if (!productProperty.Value.IsEmpty())
                                {
                                    if (property.IsSearchable.IsTrue())
                                        dynamicSearchableData.AppendFormat("{0}{1}", productProperty.Value, Environment.NewLine);

                                    productProperty.Value = productProperty.Value.HtmlEncode();
                                }
                                //property.Value = Request.Form[getDynamicControlName(property.Name)];
                                productLGL.Property.Add(productProperty);
                            }
                        }
                        entity.DynamicProperties = XmlHelper.ToString<Jb.Web.ViewModels.ZGL.Product.Product>(productLGL);
                    }
                }
            }
        }

        private String getDynamicControlName(string elementName)
        {
            return String.Format("{0}{1}", AppConstants.UI.DYNAMIC_CONTROL_PREFIX, elementName);
        }

        /// <summary>
        /// Maps JobEducations and JobSkills to ViewModel object as Expected in the Views
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="viewModel"></param>
        private void MapEducationAndSkill(Job entity, JobViewModel viewModel)
        {
            if (entity.JobEducations.Count > 0)
            {
                viewModel.Educations = (from P in entity.JobEducations where P.EducationID != null select P.EducationID.ToString()).ToArray();
                JobEducation otherEducation = entity.JobEducations.FirstOrDefault(P => P.EducationID == null);
                if (otherEducation != null)
                    viewModel.OtherEducation = otherEducation.OtherEducation;
            }
            if (entity.JobSkills.Count > 0)
            {
                viewModel.Skills = (from P in entity.JobSkills where P.SkillID != null select P.SkillID.ToString()).ToArray();
                JobSkill otherSkill = entity.JobSkills.FirstOrDefault(P => P.SkillID == null);
                if (otherSkill != null)
                    viewModel.OtherSkill = otherSkill.OtherSkill;
            }
        }

        /// <summary>
        /// Sets and Remaps Education to the Job Entity from Job View Model
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="viewModel"></param>
        private void SetJobEducations(Job entity, JobViewModel viewModel)
        {
            if (viewModel.Educations == null)
                viewModel.Educations = new String[] { };

            ///Set and Remove Within Existing Entries
            List<JobEducation> removedEducations = (from P in entity.JobEducations
                                                    where !viewModel.Educations.Contains(P.EducationID.GetValueOrDefault().ToString())
                                                        && P.EducationID != null
                                                    select P).ToList();

            foreach (var jobEducation in removedEducations)
                _Context.DeleteObject(jobEducation);

            ///Add Newly Added ones
            foreach (var educationID in viewModel.Educations)
            {
                if (educationID.ToInt() > 0 && entity.JobEducations.FirstOrDefault(P => P.EducationID == educationID.ToInt()) == null)
                    entity.JobEducations.Add(new JobEducation { JobID = entity.ID, EducationID = educationID.ToInt() });
            }
            ///Update Other Entries
            JobEducation otherEducation = entity.JobEducations.FirstOrDefault(P => P.EducationID == null);
            if (otherEducation == null)
            {
                otherEducation = new JobEducation { JobID = entity.ID, OtherEducation = viewModel.OtherEducation };
                entity.JobEducations.Add(otherEducation);
            }
            else
                otherEducation.OtherEducation = viewModel.OtherEducation;
        }
        /// <summary>
        /// Sets and Remaps Skill to the Job Entity from Job View Model
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="viewModel"></param>
        private void SetJobSkills(Job entity, JobViewModel viewModel)
        {
            if (viewModel.Skills == null)
                viewModel.Skills = new String[] { };

            ///Set and Remove Within Existing Entries
            List<JobSkill> removableSkills = (from P in entity.JobSkills
                                              where !viewModel.Skills.Contains(P.SkillID.GetValueOrDefault().ToString())
                                                  && P.SkillID != null
                                              select P).ToList();

            foreach (var jobSkill in removableSkills)
            {
                _Context.DeleteObject(jobSkill);
                //entity.JobSkills.Remove(jobSkill);
            }
            ///Set Newly added Skills
            foreach (var skillID in viewModel.Skills)
            {
                if (skillID.ToInt() > 0 && entity.JobSkills.FirstOrDefault(P => P.SkillID == skillID.ToInt()) == null)
                    entity.JobSkills.Add(new JobSkill { JobID = entity.ID, SkillID = skillID.ToInt() });
            }
            ///Update Other Entries
            JobSkill otherSkill = entity.JobSkills.FirstOrDefault(P => P.SkillID == null);
            if (otherSkill == null)
            {
                otherSkill = new JobSkill { JobID = entity.ID, OtherSkill = viewModel.OtherSkill };
                entity.JobSkills.Add(otherSkill);
            }
            else
                otherSkill.OtherSkill = viewModel.OtherSkill;
        }
        #endregion			
    }
}
